package com.example.demo43authenticationmanager.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

/**
 * 如果登录地址是 /foo/login，那么通过 wangnian 和 javaboy 两个用户可以登录成功。
 * 如果登录地址是 /bar/login，那么通过 wangnian 和 zhansgan 两个用户可以登录成功。
 * 也就是说，那个全局的，公共的 UserDetailsService 总是有效的，而针对不同过滤器链配置的 UserDetailsService 则只针对当前过滤器链生效。
 */
@Configuration
public class SecurityConfig {

    /**
     * 这里配置的 UserDetailsService 会在 AuthenticationConfiguration#initializeUserDetailsBeanManagerConfigurer#InitializeUserDetailsManagerConfigurer 注入到默认全局的 ProviderManager(AuthenticationManager的实例) 中，之后登录时如果局部的 ProviderManager 登录不成功，就会找全局的 ProviderManager。
     */
    @Bean
    UserDetailsService us() {
        InMemoryUserDetailsManager us = new InMemoryUserDetailsManager();
        us.createUser(User.withUsername("wangnian").password("{noop}123").roles("admin").build());
        return us;
    }

    @Configuration
    @Order(1)
    static class DefaultWebSecurityConfig1 extends WebSecurityConfigurerAdapter {
        UserDetailsService us1() {
            InMemoryUserDetailsManager us = new InMemoryUserDetailsManager();
            us.createUser(User.withUsername("javaboy").password("{noop}123").roles("admin").build());
            return us;
        }

        /**
         * 自定义全局的 ProviderManager，此时默认的 ProviderManager 就不会生效了。上面注入的 us Bean 就不会生效了
         */
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/foo/**")
                    .authorizeRequests()
                    .anyRequest().hasRole("admin")
                    .and()
                    .formLogin()
                    .successHandler((request, response, authentication) -> response.getWriter().write("success"))
                    .failureHandler((request, response, exception) -> response.getWriter().write("fail"))
                    .loginProcessingUrl("/foo/login")
                    .permitAll()
                    .and()
                    .userDetailsService(us1())
                    .csrf().disable();
        }
    }

    @Configuration
    @Order(2)
    static class DefaultWebSecurityConfig2 extends WebSecurityConfigurerAdapter {
        UserDetailsService us2() {
            InMemoryUserDetailsManager us = new InMemoryUserDetailsManager();
            us.createUser(User.withUsername("zhangsan").password("{noop}123").roles("user").build());
            return us;
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/bar/**")
                    .authorizeRequests()
                    .anyRequest().hasRole("user")
                    .and()
                    .formLogin()
                    .loginProcessingUrl("/bar/login")
                    .successHandler((request, response, authentication) -> response.getWriter().write("success"))
                    .failureHandler((request, response, exception) -> response.getWriter().write("fail"))
                    .permitAll()
                    .and()
                    .userDetailsService(us2())
                    .csrf().disable();
        }
    }

}
